package business.global.pk.nn;

import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import BaseCommon.CommLog;
import business.global.room.base.AbsRoomPos;
import business.global.room.base.AbsRoomSet;
import business.global.room.base.RoomPlayBack;
import business.global.union.Union;
import business.global.union.UnionMgr;
import business.nn.c2s.cclass.*;
import business.nn.c2s.iclass.*;
import business.shareplayer.SharePlayerMgr;
import cenum.PrizeType;

import cenum.RoomTypeEnum;
import cenum.room.SetState;
import cenum.room.TrusteeshipState;
import com.ddm.server.common.CommLogD;
import com.ddm.server.common.task.ScheduledExecutorServiceMgr;
import com.ddm.server.common.utils.CommMath;
import com.ddm.server.common.utils.CommTime;
import com.ddm.server.common.utils.Lists;
import com.ddm.server.common.utils.Txt2Utils;
import com.ddm.server.websocket.def.ErrorCode;
import com.ddm.server.websocket.handler.requset.WebSocketRequest;
import com.ddm.server.websocket.handler.requset.WebSocketRequestDelegate;
import com.google.gson.Gson;
import business.nn.c2s.cclass.NN_define.NN_GameStatus;
import core.db.entity.clarkGame.GameSetBO;
import core.db.service.clarkGame.GameSetBOService;
import core.ioc.ContainerMgr;
import jsproto.c2s.cclass.BaseSendMsg;
import jsproto.c2s.cclass.pk.PKRoom_RecordPosInfo;
import jsproto.c2s.cclass.pk.Victory;
import jsproto.c2s.cclass.playback.PlayBackData;
import jsproto.c2s.cclass.room.RoomPosInfo;
import org.apache.commons.collections.CollectionUtils;

import business.player.Player;
import business.player.PlayerMgr;

/**
 * 牛牛一局游戏逻辑
 *
 * @author zaf
 */

public abstract class NNRoomSet extends AbsRoomSet {

    public NNRoom room = null;
    public long startMS = 0;
    public GameSetBO bo = null;
    protected NN_GameStatus status = NN_GameStatus.NN_GAME_STATUS_HOG;
    public NNSetCard setCard = null;
    public NNRoom_SetEnd setEnd = new NNRoom_SetEnd();
    private int m_backerPos = -1; // 庄家 -1:标识没有庄家
    public boolean m_isRandBackPos = false;// 是否随机庄家
    public ArrayList<Double> sportsPointList = null;
    public ArrayList<Double> yiKaoPointList = null;

    public List<Integer> betList; // 下注分数
    public List<Boolean> robotBetList; // 机器人下注
    public List<Boolean> robotHogList; // 机器人抢庄
    public List<Boolean> robotDGNList; // 机器人抢庄
    public List<Boolean> robotCheckCard; // 机器人看牌
    public List<Boolean> checkCardList; // 亮牌玩家
    public List<Boolean> openCardList; // 开牌玩家
    public List<Boolean> playingList; // 每局玩家
    public List<Victory> callbackerList; // 是否抢过庄 victory：pos:抢庄位置 num 抢庄陪数
    public List<Integer> crawTypeList;// 牛牛类型
    public ArrayList<Integer> pointList; // 得分
    HashMap<Integer, List<Integer>> hMap = new HashMap<Integer, List<Integer>>();
    protected static final int TUIZHUSETID = 1;
    // protected static final int MAXBETNUM = 10;//推注为底分的最大陪数
    protected static final int WAITTRUSTEESHIPTIME = 3000;// 托管延迟2s
    protected static final int TUIZHULIST[] = { 0, 4, 8, 10 };
    protected RoomPlayBack roomPlayBack; // 回放
    protected boolean autoStart = true;

    int guodi;
    int guoNum;
    int guodiCur;
    int round;

    int multi;
    List<Integer> availablePosList;
    Random random = new Random();
    int selectNum;
    int currentPosIndex;
    int currentPos;
    int zhuangStatus;
    Map<Integer, Integer> winControlMap = new HashMap<>();
    int xuanZhuangNum;

    @SuppressWarnings("rawtypes")
    public NNRoomSet(NNRoom room, Map<Integer, Integer> winControlMap) {
        super(room.getCurSetID());
        this.room = room;
        this.winControlMap = winControlMap;
        this.checkCardList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.openCardList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.playingList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotHogList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotDGNList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotBetList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotCheckCard = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.betList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0));
        this.crawTypeList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0));
        this.pointList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0));
        this.callbackerList = new ArrayList<>();
        this.initSportsPointList();
        // 回放记录添加游戏配置
        this.addGameConfig();
        this.startSet();
    }

    public NNRoomSet(NNRoom room, int guodi, NNRoomSet lastSet, Map<Integer, Integer> winControlMap) {
        super(room.getCurSetID());
        this.room = room;
        this.winControlMap = winControlMap;
        this.checkCardList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.openCardList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.playingList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotHogList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotBetList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotDGNList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.robotCheckCard = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), false));
        this.betList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0));
        this.crawTypeList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0));
        this.pointList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0));
        this.callbackerList = new ArrayList<>();
        this.guodi = guodi;
        if (lastSet != null) {
            guoNum = lastSet.guoNum;
            guodiCur = lastSet.guodiCur;
            round = lastSet.round + 1;
            multi = lastSet.multi;
            currentPos = lastSet.currentPos;
            availablePosList = new ArrayList<>(lastSet.availablePosList);
        } else {
            currentPos = -1;
            multi = 1;
        }
        xuanZhuangNum = 0;
        this.initSportsPointList();
        // 回放记录添加游戏配置
        this.addGameConfig();
        this.startSet();
    }

    private void initSportsPointList() {
        if (RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
            this.sportsPointList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0D));
            // 一考分数 panvc
            this.yiKaoPointList = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0D));
        }
    }

    /**
     * 回放记录添加游戏配置
     */
    @Override
    public void addGameConfig() {
        this.getRoomPlayBack().addPlaybackList(
                SNN_Config.make(room.getRoomCfg(), this.room.getRoomTyepImpl().getRoomTypeEnum()), null);
    }

    /**
     * 获取房间回放记录
     *
     * @return
     */
    public RoomPlayBack getRoomPlayBack() {
        if (null == this.roomPlayBack) {
            this.roomPlayBack = new NNRoomPlayBackImpl(this.room);
        }
        return this.roomPlayBack;
    }

    /**
     * 每200ms更新1次 秒
     *
     * @param sec
     * @return T 是 F 否
     */
    public boolean update(int sec) {

        // if (this.room.getRoomState() == RoomState.Init) {
        // if (CommTime.nowMS() > this.startMS + this.InitTime) {
        // this.state = SetState.Playing;
        // if (!this.startNewRound()) {
        // this.endSet();
        // }
        // }
        // }
        return false;
    }

    /*
     * 开始状态
     **/
    public abstract NN_GameStatus getStartStatus();

    /*
     * 设置默认庄家位置
     **/
    public abstract void setDefeault();

    /**
     * 结算
     */
    public abstract void resultCalc();

    // 获取发牌的数目
    public abstract int getSendCardNumber();

    // 叫庄
    public void onCallBacker(WebSocketRequest request, CNN_CallBacker Backer) {
        if (this.getStatus() != NN_GameStatus.NN_GAME_STATUS_HOG) {
            request.error(ErrorCode.NotAllow, "当前不是抢庄阶段");
            return;
        }

        if (this.getCallbackerNum(Backer.pos) >= 0) {
            request.error(ErrorCode.NotAllow, "onAddScore is alary callbacker error " + Backer.pos);
            return;
        }

        // zhaozw 上庄条件
        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(Backer.pos);
        if (this.room.roomCfg.sztj > 0 && roomPos != null && roomPos.getRoomSportsPointValue() < this.room.roomCfg.sztj
                && Backer.callBackerNum > 0) {
					// 阳阳改 上庄分数不足
            //request.error(ErrorCode.NotAllow, "上庄分数不足" + Backer.pos);
            //return;
        }
        request.response();
        this.setCallBacker(Backer.pos, Backer.callBackerNum);

        // NNRoomPos roomPos = (NNRoomPos)
        // this.room.getRoomPosMgr().getPosByPosID(Backer.pos);
        if (roomPos != null && Backer.callBackerNum != 0) {
            roomPos.increaseRobCount();
        }

        this.getRoomPlayBack().playBack2All(SNN_CallBacker.make(Backer.roomID, Backer.pos, Backer.callBackerNum));

        if (this.getPlayingCount() == this.callbackerList.size()) {
            this.onHogEnd();
        }
    }

    // 下注
    public void onAddBet(WebSocketRequest request, CNN_AddBet addBet) {
        if (this.getStatus() != NN_GameStatus.NN_GAME_STATUS_BET) {
            request.error(ErrorCode.NotAllow,
                    "onAddScore is not NN_GameStatus.NN_GAME_STATUS_BET error " + this.getStatus());
            return;
        }
        if (this.getBackerPos() == addBet.pos) {
            request.error(ErrorCode.NotAllow, "onAddScore callbacker do not addbet  " + this.getBackerPos());
            return;
        }
        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(addBet.pos);
        int endPoint;
        if (this.room.getRoomCfg().difen >= 0) {
            endPoint = this.room.endPointList[this.room.getRoomCfg().difen];

        } else {
            endPoint = (int) Math
                    .floor(this.room.getRoomCfg().guodi * this.room.guodiPercentList[this.room.getRoomCfg().minbet]);
            if (endPoint == 0) {
                endPoint = 1;
            }
        }
        ArrayList<Integer> scoreList = new ArrayList<Integer>();
        scoreList.add(endPoint * 2);
        scoreList.add(endPoint);
        List<Integer> point = this.getTuZhuPoint(roomPos.getPid(), false);
        scoreList.addAll(point);

        if (!scoreList.contains(addBet.addBet)) {
            request.error(ErrorCode.NotAllow, "onAddScore not find shangzhuangfenshu error " + addBet.addBet);
            return;
        }

        if (this.betList.get(addBet.pos) > 0) {
            request.error(ErrorCode.NotAllow, "onAddScore is alary exeit error " + addBet.pos);
            return;
        }
        if (endPoint != addBet.addBet && endPoint * 2 != addBet.addBet && this.room.getRoomCfg().difen >= 0) {
            roomPos.setTuiZhu(this.room.getCurSetID() - 1, true);
            roomPos.increaseTuizhuCount();
        }
        request.response();
        this.betList.set(addBet.pos, addBet.addBet);

        this.getRoomPlayBack().playBack2All(SNN_AddBet.make(this.room.getRoomID(), addBet.pos, addBet.addBet));

        if (this.cheakAllBet()) {
            this.onBetEnd();
        }
    }

    // 下庄
    public void onShimosho(WebSocketRequest request, CNN_Shimosho addBet) {
        request.error(ErrorCode.NotAllow, "onShimosho error do not ");
    }

    // 抢庄结束
    public abstract void onHogEnd();

    /*
     * 设置状态
     */
    public void setStatus(NN_GameStatus state) {
        if (this.status == state)
            return;
        this.status = state;
        this.startMS = CommTime.nowMS();
    }

    /*
     * 获取状态
     */
    public NN_define.NN_GameStatus getStatus() {
        return this.status;
    }

    /**
     * 开始设置
     */
    public void startSet() {
        // 设置参与游戏的玩家
        for (AbsRoomPos pos : this.room.getRoomPosMgr().getPosList()) {
            NNRoomPos roomPos = (NNRoomPos) pos;
            if ((pos.isReady() && this.room.getCurSetID() == 1) || (this.room.getCurSetID() > 1 && pos.getPid() != 0)) {
                this.setPosPlaying(pos.getPosID(), true);
                roomPos.setPlayTheGame(true);
            }
        }

        // 洗底牌
        this.setCard = new NNSetCard(this);
        // 是否开启神牌模式
        if (room.isGodCard()) {
            godCard();
        }
        for (int i = 0; i < this.room.getXiPaiList().size(); i++) {
            this.setCard.onXiPai();
        }
        this.room.getXiPaiList().clear();

        // 对每个位置的人设置牌
        int index = this.room.getCurSetID();
        List<ArrayList<Integer>> lists = new ArrayList<>();
        boolean haveGod = false;
        boolean correction = false;// 是否有机器人的分数需要修正
        int godIndex = -1;
        int winIndex = -1;
        int loseIndex = -1;

        // 检查胜利控制映射表中是否存在赢家标记(1)
        if (winControlMap != null && winControlMap.containsKey(1)) {
            haveGod = true; // 设置存在神牌标记
            winIndex = winControlMap.get(1); // 获取赢家位置索引
        }
        // 检查胜利控制映射表中是否存在输家标记(0)
        if (winControlMap != null && winControlMap.containsKey(0)) {
            haveGod = true; // 设置存在神牌标记
            loseIndex = winControlMap.get(0); // 获取输家位置索引
        }

        Union union = UnionMgr.getInstance().getUnionListMgr().findUnion(this.room.roomCfg.getUnionId());
        List<AbsRoomPos> lowerLimit = new ArrayList<>();// 低于分数下限的机器人，
        List<AbsRoomPos> upperLimit = new ArrayList<>();// 高于分数上线的机器人
        List<AbsRoomPos> normal = new ArrayList<>();
        for (AbsRoomPos x : this.room.getRoomPosMgr().getPosList()) {
            if (x.getPid() > 0 && x.getPlayer().getAndroid() != 0) {
                // 由于UnionBO中没有getRobotInitScoreMin/Max方法，暂时禁用机器人分数修正功能
                // TODO: 如果需要机器人分数控制，需要在UnionBO中添加相应字段和方法
                // correction = true; // 取消注释以启用机器人处理
            }
            normal.add(x);
        }

        index = this.room.getCurSetID();
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            index = (index + 1) % this.room.getPlayerNum();
            NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(index);
            if (roomPos == null) {
                continue;
            }
            // 阳阳改 控制发牌
            // long pid = this.room.getRoomPosMgr().getPosByPosID(i).getPid();
            Player player = PlayerMgr.getInstance().getPlayer(roomPos.getPid());
            // 输出玩家信息到控制台
            System.out.println("玩家ID: " + roomPos.getPid());
            if (player == null) {
                continue;
            }
            // System.out.println("玩家信息: " + player);
            ArrayList<Integer> cards = new ArrayList<>();
            if (player != null && player.isGmLevel()) {
                System.out.println("是GM玩家" + roomPos.getPid() + "控制发牌");
                // TODO: getKongzhidian() 方法不存在，需要实现或使用其他方式获取控制点
                // cards = this.setCard.popSpecificCards(this.room.maxCardCount, player.getKongzhidian());
                cards = this.setCard.popList(this.room.maxCardCount); // 临时使用随机发牌
            } else {
                cards = this.setCard.popList(this.room.maxCardCount);
            }
            if (haveGod || correction) {
                lists.add(cards);
            } else {
                roomPos.init(cards);
            }

            // ArrayList<Integer> cards = this.setCard.popList(this.room.maxCardCount);
            // if (haveGod || correction) {
            // lists.add(cards);
            // } else {
            // roomPos.init(cards);
            // }
            // if (room.isGodCard()) {
            // // 神牌模式
            // // 获取玩家ID
            // long pid = this.room.getRoomPosMgr().getPosByPosID(i).getPid();
            // Player player = PlayerMgr.getInstance().getPlayer(pid);
            // // 输出玩家信息到控制台
            // System.out.println("玩家ID: " + pid);
            // // System.out.println("玩家信息: " + player);
            // if (player == null) {
            // continue;
            // }
            // if (player.isGmLevel()) {
            // System.out.println("玩家" + pid + "是GM");
            // roomPos.init(hMap.get(index), null, 0);
            // } else {
            // System.out.println("玩家" + pid + "不是GM");
            // roomPos.init(cards);
            // }
            // roomPos.init(this.setCard.popGoodCards(109));
            // // if (player.isGmLevel()) {
            // // roomPos.init(hMap.get(index), null, 0);
            // // } else {
            // // roomPos.init(cards);
            // // }

            // } else {
            // roomPos.init(cards);
            // }
        }

        if (correction) {
            Collections.shuffle(lowerLimit);
            Collections.shuffle(upperLimit);
            Collections.shuffle(normal);
            List<AbsRoomPos> newPosList = new ArrayList<>();
            newPosList.addAll(lowerLimit);
            newPosList.addAll(normal);
            newPosList.addAll(upperLimit);

            lists = lists.stream().sorted((x, k) -> {
                boolean result = NNGameLogic.CompareCard(x, k, getLaizi());
                return result ? -1 : 1;
            }).collect(Collectors.toList());

            for (int i = 0; i < newPosList.size(); i++) {
                NNRoomPos roomPos = (NNRoomPos) newPosList.get(i);
                if (roomPos == null) {
                    continue;
                }
                //roomPos.init(lists.get(i));  //阳阳机器人报错
            }
        }

        if (haveGod && !room.isGodCard()) {
            int maxIndex = 0;
            int minIndex = 0;
            for (int i = 1; i < lists.size(); i++) {
                if (!NNGameLogic.CompareCard(lists.get(maxIndex), lists.get(i), getLaizi())) {
                    maxIndex = i;
                }
                if (NNGameLogic.CompareCard(lists.get(minIndex), lists.get(i), getLaizi())) {
                    minIndex = i;
                }
            }
            if (maxIndex != winIndex && winIndex != -1) {
                ArrayList<Integer> l1 = lists.get(maxIndex);
                ArrayList<Integer> l2 = lists.get(winIndex);
                lists.set(winIndex, l1);
                lists.set(maxIndex, l2);
            }
            if (minIndex != loseIndex && loseIndex != -1) {
                ArrayList<Integer> l1 = lists.get(minIndex);
                ArrayList<Integer> l2 = lists.get(loseIndex);
                lists.set(loseIndex, l1);
                lists.set(minIndex, l2);
            }
            index = this.room.getCurSetID();
            for (int i = 0; i < this.room.getPlayerNum(); i++) {
                index = (index + 1) % this.room.getPlayerNum();
                NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(index);
                if (roomPos == null) {
                    continue;
                }
                roomPos.init(lists.get(index));
            }
            winControlMap.clear();
        }

        this.status = getStartStatus();
        this.startMS = CommTime.nowMS();
        this.setDefeault();

        boolean notified = false;
        // 开始发牌
        List<SNN_TuiZhuBO> maxBetPosList = Lists.newArrayList();
        for (AbsRoomPos pos : this.room.getRoomPosMgr().getAllPosList()) {
            NNRoomPos roomPos = (NNRoomPos) pos;
            if (roomPos == null) {
                continue;
            }
            long pid = roomPos.getPid();
            if (pid > 0) {
                if (!notified) {
                    notified = true;
                    this.getRoomPlayBack().playBack2Pos(roomPos,
                            SNN_SetStart.make(this.room.getRoomID(), this.getNotify_set(pid)),
                            ((NNRoomPosMgr) this.room.getRoomPosMgr()).getAllPlayBackNotify());
                } else {
                    this.room.getRoomPosMgr().notify2Pos(roomPos,
                            SNN_SetStart.make(this.room.getRoomID(), this.getNotify_set(pid)));
                }
            }
            // 发送可增加推注玩家列表可所有用户 panvc
            List<Integer> point = this.getTuZhuPoint(roomPos.getPid(), true);
            if (CollectionUtils.isNotEmpty(point)) {
                maxBetPosList.add(new SNN_TuiZhuBO(pos.getPosID(), point));
            }
        }
        // 发送可增加推注玩家列表可所有用户 panvc
        if (CollectionUtils.isNotEmpty(maxBetPosList)) {
            this.getRoomPlayBack().playBack2All(SNN_MaxBetPosList.make(maxBetPosList));
        }
        this.room.getRoomPosMgr().setAllLatelyOutCardTime();
        this.recordRoomPosPointBeginStart(); // 设置房间初始值 panvc
        this.room.getTrusteeship().setTrusteeshipState(TrusteeshipState.Normal);
    }

    public boolean isGodUser(long pid) {
        // Random random = new Random();
        // int p = random.nextInt(100);
        if (this.room.getConfigMgr().getPidList().contains((int) pid)) {// p<=this.room.getConfigMgr().getPercent()&&
            return true;
        }
        return false;
    }

    /**
     * 局结束
     */
    public void endSet() {
        if (this.status == NN_GameStatus.NN_GAME_STATUS_RESULT || this.status == NN_GameStatus.NN_GAME_STATUS_END)
            return;
        this.setStatus(NN_GameStatus.NN_GAME_STATUS_RESULT);
        setEnd(true);
        this.calcPoint();
        setRecordPosInfoList();
        // 设置默认牌为[] panvc
        ArrayList<ArrayList<Integer>> cards = new ArrayList<>(
                Collections.nCopies(this.room.getMaxPlayerNum(), Lists.newArrayList()));
        ArrayList<Integer> lastCards = new ArrayList<>(Collections.nCopies(this.room.getMaxPlayerNum(), 0));
        this.room.getRoomPosMgr().getPosList().forEach(x -> {
            if (x.getPid() > 0) {
                // cards.add(((NNRoomPos) x).getNotifyCard(x.getPid()));
                // 设置玩家的牌 panvc
                cards.set(x.getPosID(), ((NNRoomPos) x).getNotifyCard(x.getPid()));
                // lastCards.add(((NNRoomPos) x).lastCard);
                lastCards.set(x.getPosID(), ((NNRoomPos) x).lastCard);
            }
        });
        // 广播
        this.getRoomPlayBack().playBack2All(SNN_SetEnd.make(this.room.getRoomID(), this.status.value(), this.startMS,
                this.crawTypeList, this.pointList, cards, this.sportsPointList, lastCards, guodiCur));
        // 记录回放码
        roomPlayBack();// zhaozw IMPORTANT 回放
        this.setStatus(NN_GameStatus.NN_GAME_STATUS_END);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (autoStart) {
                        Thread.sleep(5000);
                        if (room != null) {
                            for (int i = 0; i < room.getPlayerNum(); i++) {

                                NNRoomPos roomPos = (NNRoomPos) room.getRoomPosMgr().getPosByPosID(i);
                                if (roomPos == null) {
                                    continue;
                                }
                                roomPos.setContinue();

                            }
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    protected void setRecordPosInfoList() {
        // 记录玩家信息和简介
        for (AbsRoomPos pos : this.room.getRoomPosMgr().getAllPosList()) {
            NNRoomPos roomPos = (NNRoomPos) pos;
            if (roomPos != null && roomPos.getPid() > 0 && roomPos.isPlayTheGame()) {
                PKRoom_RecordPosInfo posInfo = new PKRoom_RecordPosInfo();
                posInfo.flatCount = roomPos.getFlat();
                posInfo.loseCount = roomPos.getLose();
                posInfo.winCount = roomPos.getWin();
                posInfo.robCount = roomPos.getRobCount();
                posInfo.bankerCount = roomPos.getBankerCount();
                posInfo.tuizhuCount = roomPos.getTuizhuCount();

                posInfo.point = roomPos.getPoint();
                posInfo.pos = roomPos.getPosID();
                posInfo.pid = roomPos.getPid();
                posInfo.setSex(roomPos.getSex());
                posInfo.setName(roomPos.getName());
                posInfo.setSportsPoint(roomPos.sportsPoint());
                posInfo.setHeadImageUrl(roomPos.getHeadImageUrl());
                this.room.allRecordPosInfoList.put(roomPos.getPid(), posInfo);
                this.room.allPlayerList.put(roomPos.getPid(), roomPos.roomPlayerPos());
            }
        }
    }

    /**
     * 如果是房卡类型，才需要回放记录 zhaozw
     */
    public void roomPlayBack() {
        if (this.checkExistPrizeType(PrizeType.RoomCard)) {
            PlayBackData playBackData = new PlayBackData(this.room.getRoomID(),
                    this.room.getCurSetID(), 0, this.room.getCount(),
                    this.room.getRoomKey(),
                    this.room.getBaseRoomConfigure().getGameType().getId(), getPlayBackDateTimeInfo());
            this.getRoomPlayBack().addPlayBack(playBackData);
        }
    }

    // 设置所有玩家都准备进行下一场游戏
    public void setAllGameReady(boolean flag) {
        if (this.room.getCurSetID() >= this.room.getRoomCfg().getSetCount())
            return;
        for (AbsRoomPos pos : this.room.getRoomPosMgr().getPosList()) {
            if (pos.getPid() != 0) {
                pos.setGameReady(flag);
                if (flag)
                    pos.setLatelyOutCardTime(0);
            }
        }
    }

    /**
     * 结算积分
     */
    public void calcPoint() {
        GameSetBO gameSetBO = ContainerMgr.get().getComponent(GameSetBOService.class).findOne(room.getRoomID(),
                this.room.getCurSetID());
        this.bo = gameSetBO == null ? new GameSetBO() : gameSetBO;
        if (gameSetBO == null) {
            bo.setRoomID(room.getRoomID());
            bo.setSetID(this.room.getCurSetID());
            bo.setTabId(this.room.getTabId());
        }

        this.resultCalc();

        if (RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
            this.onlyWinRightNowPoint();
        }

        for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
            NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            if (roomPos != null && roomPos.getPid() > 0) {
                NNRoom_PosEnd posEnd = roomPos.calcPosEnd();
                if (CollectionUtils.isNotEmpty(this.sportsPointList)) {
                    this.sportsPointList.set(posEnd.pos, Objects.isNull(posEnd.sportsPoint) ? 0D : posEnd.sportsPoint);
                }
                this.setEnd.posResultList.add(posEnd);
            }
        }
        room.getRoomPosMgr().setAllLatelyOutCardTime();
        this.setEnd.endTime = CommTime.nowSecond();

        NNRoom_SetEnd lSetEnd = this.getNotify_setEnd();
        String gsonSetEnd = new Gson().toJson(lSetEnd);
        bo.setDataJsonRes(gsonSetEnd);
        bo.setEndTime(setEnd.endTime);
        bo.setPlayBackCode(getPlayBackDateTimeInfo().getPlayBackCode());
        bo.getBaseService().saveOrUpDate(bo);
    }

    /**
     * 获取通知设置
     *
     * @param pid 用户ID
     * @return
     */
    public NNRoomSetInfo getNotify_set(long pid) {
        NNRoomSetInfo ret = new NNRoomSetInfo();
        ret.setSetID(this.room.getCurSetID());
        ret.startTime = this.startMS;
        ret.laizi = this.getLaizi();// zhaozw
        ret.guodi = guodiCur;
        ret.guoNum = room.getDaoNum();
        ret.round = round;
        ret.sendCardNumber = this.getSendCardNumber();
        // 每个玩家的牌面
        ret.posInfo = new ArrayList<>();
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            if (roomPos == null) {
                continue;
            }
            RoomPosInfo room_Pos = this.room.getRoomPosMgr().getNotify_PosList().get(i);
            NNRoomSet_Pos roomSet_Pos = new NNRoomSet_Pos();
            int setPoint = this.pointList.get(i);
            roomSet_Pos.posID = room_Pos.getPos();
            roomSet_Pos.pid = room_Pos.getPid();
            roomSet_Pos.cards = roomPos.getNotifyCard(pid);
            roomSet_Pos.checkCard = this.checkCardList.get(i);
            roomSet_Pos.openCard = this.openCardList.get(i);
            roomSet_Pos.addBet = this.betList.get(i);
            roomSet_Pos.isPlaying = this.playingList.get(i);
            roomSet_Pos.crawType = this.crawTypeList.get(i);
            roomSet_Pos.point = this.pointList.get(i);
            roomSet_Pos.sportsPoint = roomPos.setSportsPoint(setPoint);

            ret.posInfo.add(roomSet_Pos);
        }
        ret.maxBet = this.getTuZhuPoint(pid, false);
        ret.backerPos = this.getBackerPos();
        ret.isRandBackerPos = this.isRandBackPos();
        ret.callbackerList = this.callbackerList;
        ret.state = this.status.value();
        if (this.status == NN_GameStatus.NN_GAME_STATUS_RESULT) {
            ArrayList<ArrayList<Integer>> cards = new ArrayList<>();
            ArrayList<Integer> lastCards = new ArrayList<>();
            this.room.getRoomPosMgr().getPosList().forEach(x -> {
                if (x.getPid() > 0) {
                    cards.add(((NNRoomPos) x).getNotifyCard(x.getPid()));
                    lastCards.add(((NNRoomPos) x).lastCard);
                }
            });
            SNN_SetEnd end = SNN_SetEnd.make(this.room.getRoomID(), this.status.value(), this.startMS,
                    this.crawTypeList, this.pointList, cards, this.sportsPointList, lastCards, guodiCur);
            ret.setEnd = end;
        }
        // FIXME xuanzhuang xuzhuang等状态的时候
        return ret;
    }

    /**
     * 获取通知设置结束
     *
     * @return
     */
    public NNRoom_SetEnd getNotify_setEnd() {
        return setEnd;
    }

    // 设置那些玩家在游戏中
    public void setPosPlaying(int pos, boolean flag) {
        playingList.set(pos, flag);
    }

    // 托管
    public void roomTrusteeship(int pos) {

        if (!((NNRoomPosMgr) this.room.getRoomPosMgr()).notAllTrusteeship()
                && CommTime.nowMS() - this.startMS >= WAITTRUSTEESHIPTIME)
            return;

        if (!this.playingList.get(pos))
            return;

        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(pos);
        if (roomPos == null) {
            return;
        }
        if (!(roomPos.isTrusteeship() || roomPos.isRobot()))
            return;

        switch (this.status) {
            case NN_GAME_STATUS_SELECT_BACKER:
                if (roomPos.isRobot() && pos == currentPos) {
                    if (!this.robotDGNList.get(pos)) {
                        this.robotDGNList.set(pos, true);
                        ScheduledExecutorServiceMgr.getInstance().getScheduledFuture(() -> {
                            if (zhuangStatus == 3) {
                                if (Math.random() > 0.6f) {
                                    onXiazhuang(null, CNN_Xiazhuang.make(this.room.getRoomID(), pos, 1));
                                } else {
                                    onXiazhuang(null, CNN_Xiazhuang.make(this.room.getRoomID(), pos, 0));
                                }
                            } else if (zhuangStatus == 2) {
                                NNRoomPos setpos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(currentPos);
                                if (round >= 1 && setpos != null && (setpos.getRoomSportsPoint() >= guodi * multi * 2
                                        || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum()))) {
                                    if (Math.random() > 0.6f) {
                                        onXuzhuang(null, CNN_Xuzhuang.make(this.room.getRoomID(), pos, 1));
                                    } else {
                                        onXuzhuang(null, CNN_Xuzhuang.make(this.room.getRoomID(), pos, 0));
                                    }
                                }
                            } else if (zhuangStatus == 1) {
                                if (Math.random() > 0.6f) {
                                    onXuanzhuang(null, CNN_Xuanzhuang.make(this.room.getRoomID(), pos, 1));
                                } else {
                                    onXuanzhuang(null, CNN_Xuanzhuang.make(this.room.getRoomID(), pos, 0));
                                }
                            }
                        }, (int)(Math.random() * 2000) + 1000, 0);
                    }
                }
                break;
            case NN_GAME_STATUS_HOG:
                if (this.getCallbackerNum(pos) < 0) {
                    // 机器人操作
                    if (roomPos.isRobot()) {
                        if (!this.robotHogList.get(pos)) {
                            this.robotHogList.set(pos, true);
                            if (this.room.roomCfg.sztj > 0
                                    && roomPos.getRoomSportsPointValue() < this.room.roomCfg.sztj) {
                                break;
                            }
                            ScheduledExecutorServiceMgr.getInstance().getScheduledFuture(() -> {
                                int otherMaxBackNum = CollectionUtils.isEmpty(this.callbackerList) ? 0
                                        : this.callbackerList.stream().max(Comparator.comparingInt(Victory::getNum))
                                                .get().getNum();
                                int callBackNum = new Random().nextInt(this.room.roomCfg.zuidaqiangzhuang + 1);
                                if (CollectionUtils.isNotEmpty(roomPos.privateCards)) {
                                    ArrayList<Integer> handCards = new ArrayList<>(roomPos.privateCards.subList(0, 4));
                                    int cardType = NNGameLogic.GetCardType2(handCards, this.getLaizi());
                                    if (cardType > 0) {
                                        // 牛1-牛6概率抢庄 牛7-满牛必抢庄 没牛不抢
                                        if ((int)(Math.random() * 7) < cardType) {
                                            for (int i = this.room.roomCfg.zuidaqiangzhuang + 1; i > 0; i--) {
                                                // 满牛最大倍抢庄
                                                if ((int)(Math.random() * 10) < cardType) {
                                                    callBackNum = i;
                                                    break;
                                                }
                                            }
                                            callBackNum = callBackNum == 0 ? 1 : callBackNum;
                                        }
                                    } else {
                                        callBackNum = 0;
                                    }
                                }
                                if (callBackNum < otherMaxBackNum) {
                                    callBackNum = 0;
                                }
                                if (callBackNum == 0) {
                                    // 不抢庄的牌有5%的概率不做任何动作
                                    if (Math.random() > 0.05) {
                                        onCallBacker(new WebSocketRequestDelegate(),
                                                CNN_CallBacker.make(this.room.getRoomID(), pos, callBackNum));
                                    }
                                } else {
                                    onCallBacker(new WebSocketRequestDelegate(),
                                            CNN_CallBacker.make(this.room.getRoomID(), pos, callBackNum));
                                }
                            }, (int)(Math.random() * (getWaitTimeByStatus() - 1000)) + 500, 0);
                        }
                    } else {
                        int callBackNum = 0;
                        this.setCallBacker(pos, callBackNum);
                        this.getRoomPlayBack()
                                .playBack2All(SNN_CallBacker.make(this.room.getRoomID(), pos, callBackNum));
                    }
                }

                if (this.getPlayingCount() == this.callbackerList.size()) {
                    this.onHogEnd();
                }
                break;
            case NN_GAME_STATUS_BET:
                int endPoint;
                if (this.room.getRoomCfg().difen >= 0) {
                    endPoint = this.room.endPointList[this.room.getRoomCfg().difen];
                } else {
                    endPoint = (int) Math.floor(
                            this.room.getRoomCfg().guodi * this.room.guodiPercentList[this.room.getRoomCfg().minbet]);
                    if (endPoint == 0) {
                        endPoint = 1;
                    }
                }

                if (this.getBackerPos() == pos)
                    break;
                if (this.betList.get(pos) > 0)
                    break;

                // 机器人操作
                if (roomPos.isRobot()) {
                    if (!this.robotBetList.get(pos)) {
                        this.robotBetList.set(pos, true);
                        int addBet = endPoint;
                        if (CollectionUtils.isNotEmpty(roomPos.privateCards)) {
                            ArrayList<Integer> handCards = new ArrayList<>(roomPos.privateCards.subList(0, 4));
                            int cardType = NNGameLogic.GetCardType2(handCards, this.getLaizi());
                            if (cardType > 0) {
                                double odds = 0.1 * (cardType > 6 ? cardType : cardType / 2.0);// 牛七以下牌型每注概率减半
                                List<Integer> betList = new ArrayList<>(Arrays.asList(endPoint, endPoint * 2));
                                betList.addAll(this.getTuZhuPoint(roomPos.getPid(), false));
                                for (int i = betList.size() - 1; i > 0; i--) {
                                    if (Math.random() < odds) {
                                        addBet = betList.get(i);
                                        break;
                                    }
                                }
                            }
                        }
                        int finalAddBet = addBet;
                        ScheduledExecutorServiceMgr.getInstance().getScheduledFuture(() -> {
                            onAddBet(new WebSocketRequestDelegate(),
                                    CNN_AddBet.make(this.room.getRoomID(), pos, finalAddBet));
                        }, (int)(Math.random() * (getWaitTimeByStatus() - 1000)) + 500, 0);
                    }
                } else {
                    this.betList.set(pos, endPoint);
                    this.getRoomPlayBack().playBack2All(SNN_AddBet.make(this.room.getRoomID(), pos, endPoint));
                }

                if (this.cheakAllBet()) {
                    this.onBetEnd();
                }
                break;
            case NN_GAME_STATUS_SENDCARD_SECOND:
                // 机器人操作
                if (roomPos.isRobot()) {
                    if (!this.robotCheckCard.get(pos)) {
                        try {
                            this.robotCheckCard.set(pos, true);
                            // 有5%的概率不做任何动作
                            if (Math.random() > 0.05) {
                                ScheduledExecutorServiceMgr.getInstance().getScheduledFuture(() -> {
                                    onCheckCard(new WebSocketRequestDelegate(),
                                            CNN_CheckCard.make(this.room.getRoomID(), pos));
                                }, (int)(Math.random() * (getWaitTimeByStatus() - 3000)) + 500, 0);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    if (!this.checkCardList.get(pos))
                        this.checkCardList.set(pos, true);
                    if (!this.openCardList.get(pos)) {
                        this.openCardList.set(pos, true);
                        this.getRoomPlayBack().playBack2All(
                                SNN_OpenCard.make(this.room.getRoomID(), pos, false, new ArrayList<Integer>()));
                    }
                }

                if (this.cheakAllOpenCard()) {
                    this.onSendCardEnd();
                }
                break;
            case NN_GAME_STATUS_RESULT:
                if (!roomPos.isGameReady()) {
                    roomPos.setGameReady(true);
                    roomPos.setLatelyOutCardTime(0);
                }

                break;
            default:
                break;
        }
    }

    // 翻牌
    public void onOpenCard(WebSocketRequest request, CNN_OpenCard openCard) {
        if (this.getStatus() != NN_GameStatus.NN_GAME_STATUS_SENDCARD_SECOND) {
            request.error(ErrorCode.NotAllow,
                    "onAddScore is not NN_GameStatus.NN_GAME_STATUS_SendCard error " + this.getStatus());
            return;
        }

        if (this.openCardList.get(openCard.pos)) {
            request.error(ErrorCode.NotAllow, "onAddScore is alary opend  error " + openCard.pos);
            return;
        }

        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(openCard.pos);

        if (roomPos != null) {
            ArrayList<Integer> cards = new ArrayList<>(roomPos.privateCards);
            int type = NNGameLogic.GetCardType(cards, getLaizi());
            // 新增pos panvc
            request.response(SNN_CheckCard.make(openCard.pos, cards, type, roomPos.lastCard));
        } else {
            request.response();
        }
        // request.response();
        this.openCardList.set(openCard.pos, true);

        if (openCard.isSelectCard) {
            // NNRoomPos roomPos = (NNRoomPos)
            // this.room.getRoomPosMgr().getPosByPosID(openCard.pos);
            if (roomPos != null && this.checkCardList(openCard.pos, openCard.cardList))
                roomPos.init(openCard.cardList);
        }

        this.getRoomPlayBack().playBack2All(
                SNN_OpenCard.make(this.room.getRoomID(), openCard.pos, openCard.isSelectCard, openCard.cardList));
        if (this.cheakAllOpenCard()) {
            this.onSendCardEnd();
        }
    }

    // 翻牌
    public void onCheckCard(WebSocketRequest request, CNN_CheckCard checkCard) {
        if (this.getStatus() != NN_GameStatus.NN_GAME_STATUS_SENDCARD_SECOND) {
            request.error(ErrorCode.NotAllow,
                    "onAddScore is not NN_GameStatus.NN_GAME_STATUS_SendCard error " + this.getStatus());
            return;
        }
        if (this.checkCardList.get(checkCard.pos)) {
            request.error(ErrorCode.NotAllow, "onAddScore is alary checkCard  error " + checkCard.pos);
            return;
        }
        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(checkCard.pos);

        if (roomPos != null) {
            ArrayList<Integer> cards = new ArrayList<>(roomPos.privateCards);
            int type = NNGameLogic.GetCardType(cards, getLaizi());
            // 通知每个玩家翻牌信息 panvc
            request.response(SNN_CheckCard.make(checkCard.pos, cards, type, roomPos.lastCard));
            this.getRoomPlayBack().playBack2All(SNN_CheckCard.make(checkCard.pos, cards, type, roomPos.lastCard));
        } else {
            request.response();
        }
        this.checkCardList.set(checkCard.pos, true);

        if (this.cheakAllOpenCard2()) {
            this.onSendCardEnd();
        }
    }

    public boolean cheakAllOpenCard2() {
        for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
            if (this.playingList.get(i) && !this.checkCardList.get(i)) {
                return false;
            }
        }
        return true;
    }

    // 当前几个人在玩
    public int getPlayingCount() {
        int count = 0;
        for (boolean flag : this.playingList) {
            if (flag)
                count++;
        }
        return count;
    }

    // 是否所有玩家都下注
    public boolean cheakAllBet() {
        for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
            if (i == this.getBackerPos())
                continue;
            if (this.playingList.get(i) && this.betList.get(i) <= 0) {
                return false;
            }
        }
        return true;
    }

    // 是否所有玩家都开牌
    public boolean cheakAllOpenCard() {
        for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
            if (this.playingList.get(i) && !this.openCardList.get(i)) {
                return false;
            }
        }
        return true;
    }

    /*
     * 设置是否抢庄
     */
    public void setCallBacker(int pos, int callBackerNum) {
        boolean flag = false;
        try {
            if (this.callbackerList.size() > 0) {
                for (Victory vic : this.callbackerList) {
                    if (null == vic)
                        continue;
                    if (pos == vic.getPos()) {
                        vic.setNum(callBackerNum);
                        flag = true;
                    }
                }
            }
            if (!flag) {
                if (this.callbackerList == null)
                    this.callbackerList = new ArrayList<Victory>();
                Victory vic = new Victory(pos, callBackerNum);
                this.callbackerList.add(vic);
            }
        } catch (Exception e) {
            CommLogD.error("getCallbackerNum error:", e);
        }
        return;
    }

    /*
     * 抢庄倍数
     */
    @SuppressWarnings("finally")
    public int getCallbackerNum(int pos) {
        int flag = -1;
        try {
            if (this.callbackerList.size() <= 0)
                return flag;
            for (Victory vic : this.callbackerList) {
                if (null == vic)
                    continue;
                if (vic.getPos() == pos) {
                    flag = vic.getNum();
                    break;
                }
            }
            // CommLogD.info("getCallbackerNum num:%s ,pos:%s", flag, pos);
            // if(this.callbackerList.size() > 0) {
            // CommLogD.info("this.callbackerList.toString():%s",
            // this.callbackerList.toString());
            // }
        } catch (Exception e) {
            CommLogD.error("getCallbackerNum error:", e);
        } finally {
            return flag;
        }
    }

    // 有没有抢庄的
    @SuppressWarnings("finally")
    public int getCallBackerCount() {
        int count = 0;
        try {
            if (this.callbackerList.size() <= 0)
                return count;
            for (Victory vic : this.callbackerList) {
                if (null == vic)
                    continue;
                if (vic.getNum() >= 1) {
                    count++;
                }
            }
        } catch (Exception e) {
            CommLogD.error("getCallBackerCount error:", e);
        } finally {
            return count;
        }
    }

    // 获取阶段时间
    public int getWaitTimeByStatus() {
        int waitTime = 0;
        switch (this.status) {
            case NN_GAME_STATUS_SELECT_BACKER:
                waitTime = 50000;
                break;
            case NN_GAME_STATUS_SENDCARD_ONE:
                waitTime = 1000;
                break;
            case NN_GAME_STATUS_HOG:
                waitTime = 6000;
                break;
            case NN_GAME_STATUS_ONSURECALLBACKER:
                waitTime = 2000;
                break;
            case NN_GAME_STATUS_BET:
                waitTime = 5000;
                break;
            case NN_GAME_STATUS_SENDCARD_SECOND:  //阳阳 开牌时间
                waitTime = 10000;
                break;
            case NN_GAME_STATUS_RESULT:
                waitTime = 0;
                break;
            default:
                break;
        }
        return waitTime;
    }

    /**
     * @return backerPos
     */
    public int getBackerPos() {
        return this.m_backerPos;
    }

    /**
     * @param backerPos 要设置的 backerPos
     */
    public void setBackerPos(int backerPos, boolean isRandBackerPos) {
        this.m_backerPos = backerPos;
        this.m_isRandBackPos = isRandBackerPos;

        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(backerPos);
        if (roomPos != null) {
            roomPos.increaseBankerCount();
        }
        if (this.getCallbackerNum(backerPos) <= 0)
            this.setCallBacker(backerPos, 1);
    }

    /*
     * 牌验证
     **/
    public boolean checkCardList(int pos, ArrayList<Integer> cardList) {
        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(pos);
        if (roomPos == null) {
            return true;
        }
        for (Integer byte1 : cardList) {
            if (!roomPos.privateCards.contains(byte1)) {
                return false;
            }
        }
        return true;
    }

    // 庄家确认结束
    public void onSureCallbacker() {
        this.setStatus(NN_GameStatus.NN_GAME_STATUS_BET);
        this.sendTuZhuPoint();
    }

    // 下注结束
    public void onBetEnd() {
        for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
            if (!this.playingList.get(i))
                continue;
            if (this.getBackerPos() == i)
                continue;

            if (this.playingList.get(i) && this.betList.get(i) == 0) {
                // int bet = this.room.endPointList[this.room.roomCfg.difen];
                int bet;
                if (this.room.getRoomCfg().difen >= 0) {
                    bet = this.room.endPointList[this.room.getRoomCfg().difen];
                } else {
                    bet = (int) Math.floor(
                            this.room.getRoomCfg().guodi * this.room.guodiPercentList[this.room.getRoomCfg().minbet]);
                    if (bet == 0) {
                        bet = 1;
                    }
                }
                this.betList.set(i, bet);
                this.getRoomPlayBack().playBack2All(SNN_AddBet.make(this.room.getRoomID(), i, bet));
            }
        }
        this.setStatus(NN_GameStatus.NN_GAME_STATUS_SENDCARD_SECOND);

        this.getRoomPlayBack()
                .playBack2All(SNN_StatusChange.make(this.room.getRoomID(), this.getStatus().value(), this.startMS,
                        this.getSendCardNumber(), this.getBackerPos(), this.isRandBackPos(), new ArrayList<>(),
                        this.callbackerList));
    }

    // 发牌结束
    public void onSendCardEnd() {
        for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
            if (this.playingList.get(i) && this.openCardList.get(i) == false) {
                this.getRoomPlayBack()
                        .playBack2All(SNN_OpenCard.make(this.room.getRoomID(), i, false, new ArrayList<Integer>()));
            }
        }
        this.endSet();
    }

    // 在玩家中随机一个玩家位置出来
    public int getRandPos() {
        int randPos = (int) (Math.random() * this.room.getPlayingCount());
        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(randPos);
        if (!this.playingList.get(randPos) || (this.room.roomCfg.sztj > 0 && roomPos != null
                && roomPos.getRoomSportsPointValue() < this.room.roomCfg.sztj)) {
            for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
                randPos = (randPos + 1) % this.room.getMaxPlayerNum();
                roomPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(randPos);
                if (this.playingList.get(randPos) && (this.room.roomCfg.sztj <= 0 || this.room.roomCfg.sztj > 0
                        && roomPos != null && roomPos.getRoomSportsPointValue() >= this.room.roomCfg.sztj)) {
                    break;
                }
            }
        }
        return randPos;
    }

    // 下发推注分数
    public void sendTuZhuPoint() {
        boolean notified = false;
        // List<SNN_TuiZhuBO> maxBetPosList = Lists.newArrayList();
        // 获取最大的抢庄倍数 panvc
        int numMax = callbackerList.stream().mapToInt(Victory::getNum).max().getAsInt();
        List<Integer> posList;
        if (0 == numMax) {
            posList = Collections.emptyList();
        } else {
            posList = callbackerList.stream().filter(k -> k.getNum() == numMax).map(Victory::getPos)
                    .collect(Collectors.toList());
        }
        for (AbsRoomPos pos : this.room.getRoomPosMgr().getAllPosList()) {
            NNRoomPos roomPos = (NNRoomPos) pos;
            if (roomPos == null || roomPos.getPid() == 0)
                continue;

            List<Integer> point;
            // 判断当局是否抢庄
            if (CollectionUtils.isEmpty(posList) || !posList.contains(pos.getPosID())) {
                point = Collections.emptyList();
            } else {
                point = this.getTuZhuPoint(roomPos.getPid(), false);
            }
            if (!notified) {
                notified = true;
                this.getRoomPlayBack().playBack2Pos(pos,
                        SNN_StatusChange.make(this.room.getRoomID(), this.getStatus().value(), this.startMS, 0,
                                this.getBackerPos(), this.isRandBackPos(), point, this.callbackerList, guodiCur, guoNum,
                                room.getDaoNum()),
                        ((NNRoomPosMgr) this.room.getRoomPosMgr()).getAllPlayBackNotify());
            } else {
                this.room.getRoomPosMgr().notify2Pos(pos,
                        SNN_StatusChange.make(this.room.getRoomID(), this.getStatus().value(), this.startMS, 0,
                                this.getBackerPos(), this.isRandBackPos(), point, this.callbackerList, guodiCur, guoNum,
                                room.getDaoNum()));
            }
            /*
             * if(CollectionUtils.isNotEmpty(point)){
             * maxBetPosList.add(new SNN_TuiZhuBO(pos.getPosID(), point));
             * }
             */
        }
        /*
         * //发送可增加推注玩家列表可所有用户 panvc
         * if(CollectionUtils.isNotEmpty(maxBetPosList)){
         * this.getRoomPlayBack().playBack2All(SNN_MaxBetPosList.make(maxBetPosList));
         * }
         */
    }

    /**
     * 获取推注分数
     *
     * @param pid
     * @param checkZhuang 校验庄 false：需要校验 true :不需要校验 panvc
     * @return
     */
    public List<Integer> getTuZhuPoint(long pid, boolean checkZhuang) {
        List<Integer> result = new ArrayList<>();
        NNRoomPos roomPos = (NNRoomPos) this.room.getRoomPosMgr().getAllPosByPid(pid);
        int curSetID = this.room.getCurSetID();
        // CommLogD.info("this.room.roomCfg.isXianJiaTuiZhu:%s this.getBackerPos():%d
        // roomPos.posID:%d roomPos.point:%d "
        // + "!roomPos.isTuiZhu(curSetID - 1):%s curSetID:%d\n",
        // this.room.roomCfg.isXianJiaTuiZhu, this.getBackerPos() , roomPos.posID ,
        // roomPos.point , !roomPos.isTuiZhu(curSetID - 1) , curSetID );

        // boolean isGold = PrizeType.Gold ==
        // this.room.getBaseRoomConfigure().getPrizeType() ? true : false;
        if (RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {

            if (this.room.roomCfg.isXianJiaTuiZhu > 0 && (checkZhuang || this.getBackerPos() != roomPos.getPosID())
                    && (roomPos.getRoomSportsPointValue() > 0
                            || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum()))
                    && curSetID > TUIZHUSETID
                    && !roomPos.isTuiZhu(curSetID - 1 - 1) && !roomPos.isVisitor()) {// zhaozw 数组从0开始，cursetid从1开始
                if (this.isCanTuiZhu(roomPos.getPosID())) {
                    // int bet = this.room.endPointList[this.room.roomCfg.difen];
                    int bet;
                    if (this.room.getRoomCfg().difen >= 0) {
                        bet = this.room.endPointList[this.room.getRoomCfg().difen];
                    } else {
                        bet = (int) Math.floor(this.room.getRoomCfg().guodi
                                * this.room.guodiPercentList[this.room.getRoomCfg().minbet]);
                        if (bet == 0) {
                            bet = 1;
                        }
                    }
                    if (this.room.roomCfg.isXianJiaTuiZhu == 3) {
                        // 上局是否抢庄，上局是否赢，并且牌型倍数大于1（留7以上） panvc
                        if (roomPos.isQiangzhuang(curSetID - 2) && roomPos.getBeishu(curSetID - 2) > 1) {
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[1]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[1]);
                            }
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[2]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[2]);
                            }
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[3]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[3]);
                            }
                        } else if (roomPos.getBeishu(curSetID - 2) > 1) {
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[1]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[1]);
                            }
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[2]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[2]);
                            }
                        } else {
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[1]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[1]);
                            }
                        }
                    } else if (this.room.roomCfg.isXianJiaTuiZhu == 2) {
                        if (roomPos.getBeishu(curSetID - 2) > 1) {
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[1]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[1]);
                            }
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[2]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[2]);
                            }
                        } else {
                            if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[1]
                                    || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                                result.add(bet * TUIZHULIST[1]);
                            }
                        }
                    } else {
                        if (roomPos.getRoomSportsPointValue() > bet * TUIZHULIST[1]
                                || !RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
                            result.add(bet * TUIZHULIST[1]);
                        }
                    }
                }
            }
        } else {

            if (this.room.roomCfg.isXianJiaTuiZhu > 0 && (checkZhuang || this.getBackerPos() != roomPos.getPosID())
                    && curSetID > TUIZHUSETID
                    && !roomPos.isTuiZhu(curSetID - 1 - 1) && !roomPos.isVisitor()) {// zhaozw 数组从0开始，cursetid从1开始
                if (this.isCanTuiZhu(roomPos.getPosID())) {
                    // int bet = this.room.endPointList[this.room.roomCfg.difen];
                    int bet;
                    if (this.room.getRoomCfg().difen >= 0) {
                        bet = this.room.endPointList[this.room.getRoomCfg().difen];
                    } else {
                        bet = (int) Math.floor(this.room.getRoomCfg().guodi
                                * this.room.guodiPercentList[this.room.getRoomCfg().minbet]);
                        if (bet == 0) {
                            bet = 1;
                        }
                    }
                    if (this.room.roomCfg.isXianJiaTuiZhu == 3) {
                        if (roomPos.isQiangzhuang(curSetID - 2) && roomPos.getBeishu(curSetID - 2) > 1) {
                            result.add(bet * TUIZHULIST[1]);
                            result.add(bet * TUIZHULIST[2]);
                            result.add(bet * TUIZHULIST[3]);
                        } else if (roomPos.getBeishu(curSetID - 2) > 1) {
                            result.add(bet * TUIZHULIST[1]);
                            result.add(bet * TUIZHULIST[2]);
                        } else {
                            result.add(bet * TUIZHULIST[1]);
                        }
                    } else if (this.room.roomCfg.isXianJiaTuiZhu == 2) {
                        if (roomPos.getBeishu(curSetID - 2) > 2) {
                            result.add(bet * TUIZHULIST[1]);
                            result.add(bet * TUIZHULIST[2]);
                        } else {
                            result.add(bet * TUIZHULIST[1]);
                        }
                    } else {
                        result.add(bet * TUIZHULIST[1]);
                    }
                }
            }
        }
        return result;
    }

    /*
     * 获取上一句是否是闲家 且是否赢了
     */
    public boolean isCanTuiZhu(int pos) {
        boolean flag = false;
        NNRoomSet set = this.getHisSet(this.room.getCurSetID() - 1 - 1);
        if (null == set) {
            return flag;
        }
        int lastPoint = set.pointList.get(pos);
        if (set.m_backerPos != pos && lastPoint > 0) {
            flag = true;
        }
        return flag;
    }

    // 获取历史set
    public NNRoomSet getHisSet(int setID) {
        if (room.getHistorySetSize() > setID)
            return (NNRoomSet) room.getHistorySet(setID);
        return null;
    }

    /**
     * 设置神牌
     */
    private void godCard() {
        if (!room.isGodCard()) {
            return;
        }
        int cardNum = this.room.maxCardCount;
        // boolean flag1 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card1());
        // boolean flag2 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card2());
        // boolean flag3 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card3());
        // boolean flag4 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card4());
        // boolean flag5 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card5());
        // boolean flag6 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card6());
        // boolean flag7 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card7());
        // boolean flag8 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(),
        // room.getConfigMgr().getPrivate_Card8());
        // if (flag1 && flag2 && flag3 ) {
        ArrayList<Integer> card1 = getGodCard(room.getConfigMgr().getPrivate_Card1());
        ArrayList<Integer> card2 = getGodCard(room.getConfigMgr().getPrivate_Card2());
        ArrayList<Integer> card3 = getGodCard(room.getConfigMgr().getPrivate_Card3());
        // ArrayList<Integer> card4 =
        // getGodCard(room.getConfigMgr().getPrivate_Card4());
        // ArrayList<Integer> card5 =
        // getGodCard(room.getConfigMgr().getPrivate_Card5());
        // ArrayList<Integer> card6 =
        // getGodCard(room.getConfigMgr().getPrivate_Card6());
        // ArrayList<Integer> card7 =
        // getGodCard(room.getConfigMgr().getPrivate_Card7());
        // ArrayList<Integer> card8 =
        // getGodCard(room.getConfigMgr().getPrivate_Card8());
        hMap.put(0, card1);
        hMap.put(1, card2);
        hMap.put(2, card3);
        // hMap.put(3, card4);
        // hMap.put(4, card5);
        // hMap.put(5, card6);
        // hMap.put(6, card7);
        // hMap.put(7, card8);
        // } else {
        // hMap.put(0, this.setCard.popList(cardNum));
        // hMap.put(1, this.setCard.popList(cardNum));
        // hMap.put(2, this.setCard.popList(cardNum));
        // }
        // hMap.put(3, this.setCard.popList(cardNum));
        // hMap.put(4, this.setCard.popList(cardNum));
        // hMap.put(5, this.setCard.popList(cardNum));
        // hMap.put(6, this.setCard.popList(cardNum));
        // hMap.put(7, this.setCard.popList(cardNum));
        // hMap.put(8, this.setCard.popList(cardNum));
        // hMap.put(9, this.setCard.popList(cardNum));
    }

    /**
     * 插入牌 并在牌堆里面删除
     */
    public ArrayList<Integer> getGodCard(ArrayList<Integer> list) {
        if (!room.isGodCard()) {
            return new ArrayList<>();
        }
        int cardNum = this.room.maxCardCount;
        ArrayList<Integer> cardList = new ArrayList<Integer>(cardNum);
        cardList.addAll(list);
        int count = cardNum - cardList.size();
        ArrayList<Integer> tempList = this.setCard.popList(count);
        BasePockerLogic.deleteCard(this.setCard.getLeftCards(), tempList);
        cardList.addAll(tempList);
        return cardList;
    }

    /**
     * @return m_isRandBackPos
     */
    public boolean isRandBackPos() {
        return m_isRandBackPos;
    }

    @Override
    public void clear() {
        this.room = null;
        if (null != this.setCard) {
            this.setCard = null;
        }
        // this.pointList = null;
        this.openCardList = null;
        this.setEnd = null;
        this.hMap = null;
    }

    @Override
    public void addDissolveRoom(BaseSendMsg baseSendMsg) {
        if (this.status == NN_define.NN_GameStatus.NN_GAME_STATUS_RESULT) {
            return;
        }
        NNRoomPosMgr roomPosMgr = (NNRoomPosMgr) this.room.getRoomPosMgr();
        this.getRoomPlayBack().addPlaybackList(baseSendMsg, roomPosMgr.getAllPlayBackNotify());
    }

    @Override
    public boolean checkExistPrizeType(PrizeType prizeType) {
        return prizeType.equals(this.room.getBaseRoomConfigure().getPrizeType());
    }

    @Override
    public void clearBo() {
        this.bo = null;
    }

    /**
     * 标识Id
     *
     * @return
     */
    @Override
    public int getTabId() {
        return this.room.getTabId();
    }

    public int getLaizi() {
        return setCard.getLaizi();
    }

    public void onXuanzhuang(WebSocketRequest request, CNN_Xuanzhuang req) {
    }

    public void onXuzhuang(WebSocketRequest request, CNN_Xuzhuang req) {
    }

    public void onXiazhuang(WebSocketRequest request, CNN_Xiazhuang req) {

    }

    public void onWinControl(WebSocketRequest request, CNN_WinControl req) {
        winControlMap.put(req.flag, req.pos);
    }

    @Override
    public void recordRoomPosPointBeginStart() {
        if (this.room.isOnlyWinRightNowPoint() && RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
            for (int i = 0; i < room.getPlayerNum(); i++) {
                AbsRoomPos roomPos = this.room.getRoomPosMgr().getPosByPosID(i);
                roomPos.setGameBeginSportsPoint(roomPos.getRoomSportsPoint());
            }
        }
    }

    /**
     * 》》1.获取庄家并得到输家和赢家列表并排序
     * 1.1 获取庄家
     * 1.2 输家从小到大
     * 1.3 赢家从大到小
     * 》》2.计算庄家赢得分
     * 2.1 设置能赢分总和
     * 2.2 累加从输家能赢到的竞技点，加满赢分总和或者算完输家位数
     * 》》3.计算庄家输分
     * 3.1 计算当前赢的闲家赢分总数
     * 3.2 计算庄家是否够赔。够赔，则计算下一赢的闲家， 不够赔则，庄家分扣完，计算结束
     * 4. 设置庄家分
     */
    @SuppressWarnings("Duplicates")
    public void onlyWinRightNowPoint() {
        // 各个位置的算分情况map
        double beiShu = Math.max(0D, this.room.getRoomTyepImpl().getSportsDouble());
        // 获取庄家
        NNRoomSet set = (NNRoomSet) this.room.getCurSet();
        // 没有庄家,不做计算
        if (-1 == set.getBackerPos()) {
            return;
        }
        NNRoomPos setDPos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(set.getBackerPos());
        // 设置庄家信息
        ArrayList<Integer> callBackerCardList = (ArrayList<Integer>) setDPos.privateCards.clone();
        List<NNRoomPos> winPosList = new ArrayList<>();
        List<NNRoomPos> losePosList = new ArrayList<>();
        for (int i = 0; i < this.room.getMaxPlayerNum(); i++) {
            if (!(boolean) set.playingList.get(i)) {
                continue;
            }
            if (i == set.getBackerPos()) {
                continue;
            }
            NNRoomPos setpos = (NNRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            if (NNGameLogic.CompareCard(callBackerCardList, setpos.privateCards, set.getLaizi())) {
                losePosList.add(setpos);
            } else {
                winPosList.add(setpos);
            }
        }
        // 赢家从大到小排序
        Collections.sort(winPosList,
                (o1, o2) -> NNGameLogic.CompareCard(o1.privateCards, o2.privateCards, set.getLaizi()) ? -1 : 1);
        // 输家从小到大排序
        Collections.sort(losePosList,
                (o1, o2) -> NNGameLogic.CompareCard(o2.privateCards, o1.privateCards, set.getLaizi()) ? -1 : 1);

        // 庄家可赢分
        Double dSportPoint = setDPos.getGameBeginSportsPoint();
        // 输的闲家计算
        for (NNRoomPos lose : losePosList) {
            if (dSportPoint == 0) {
                break;
            }
            if (lose.getPosID() < 0) {
                continue;
            }
            // 计算输分值
            Double point = Math.abs(CommMath.mul(pointList.get(lose.getPosID()), beiShu));
            if (lose.getGameBeginSportsPoint() <= point) {
                point = lose.getGameBeginSportsPoint();
            }
            if (point >= dSportPoint) {
                point = dSportPoint;
            }
            // 计算庄家可赢分
            dSportPoint = CommMath.subDouble(dSportPoint, point);
            yiKaoPointList.set(lose.getPosID(), -point);
        }
        // 庄家当前身上分 = 2倍可赢分 - 剩余的庄家可赢分
        double dSportPointNow = CommMath.addDouble(setDPos.getGameBeginSportsPoint(),
                CommMath.subDouble(setDPos.getGameBeginSportsPoint(), dSportPoint));
        // 赢得闲家计算
        for (NNRoomPos win : winPosList) {
            if (dSportPointNow == 0) {
                break;
            }
            if (win.getPosID() < 0) {
                continue;
            }
            // 计算赢分值
            Double point = CommMath.mul(pointList.get(win.getPosID()), beiShu);
            if (win.getGameBeginSportsPoint() <= point) {
                point = win.getGameBeginSportsPoint();
            }
            if (point >= dSportPointNow) {
                point = dSportPointNow;
            }
            // 庄家当前身上分
            dSportPointNow = CommMath.subDouble(dSportPointNow, point);
            yiKaoPointList.set(win.getPosID(), point);
        }
        // 设置庄家一考分
        yiKaoPointList.set(setDPos.getPosID(), CommMath.subDouble(dSportPointNow, setDPos.getGameBeginSportsPoint()));
    }

}
